package com.zyf.service.video;

import cn.hutool.core.io.FileUtil;
import com.zyf.service.audio.HandleAudioService;
import com.zyf.utils.FFmpegUtils;
import org.bytedeco.ffmpeg.global.avcodec;
import org.bytedeco.ffmpeg.global.avutil;
import org.bytedeco.javacv.*;

import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import java.io.*;
import java.util.*;

/**
 * 视频处理类
 */
public class VedioUtils {

    /**
     * 批量提取视频
     *
     * @throws Exception
     */
    public String splitVedios(String fileDestory) throws Exception {
        String result = "提取成功";

        List<File> fileList = FileUtil.loopFiles(fileDestory, file -> file.isFile() && file.getName().endsWith(".mp4"));
        if (fileList == null || fileList.size() < 1) {
            return result;
        }
        for (File paramfile : fileList) {
            String videoFile = paramfile.getAbsolutePath();
            try {
                splitSingleVideo(videoFile);
            } catch (Exception e) {
                result = e.toString();
            }
        }

        return result;
    }

    /**
     * 分离视频并合并视频
     *
     * @throws Exception
     */
    public void splitAndMergeVedios(String fileDestory) throws Exception {
        //分离音频
        splitVedios(fileDestory);
        //合并视频
        batchMergeVedios(fileDestory);
    }

    /**
     * 合并音频
     */
    public void batchMergeAudios(String audiopath) throws Exception {
        File txt = new File(audiopath, "audiofilelist.txt");
        if (txt.exists()) {
            txt.delete();
        }
        txt = new File(audiopath, "audiofilelist.txt");
        List<File> fileList = FileUtil.loopFiles(audiopath, file -> file.isFile() && file.getName().endsWith(".mp3"));
        List<String> Mp4List = new ArrayList<>();
        for (File file : fileList) {
            Mp4List.add("file \'" + file.getAbsolutePath() + "\'");
        }
        //将数组内容写入文本文件文件filelist.txt
        FileUtil.writeLines(Mp4List, txt, "utf-8", false);

        List<String> commands = new ArrayList<>();
        commands.add("ffmpeg");
        commands.add("-f");
        commands.add("concat");
        commands.add("-i");
        commands.add(txt.getAbsolutePath());
        commands.add("-c");
        commands.add("copy");
        commands.add(audiopath + File.separator + "merged_audio.mp3");
        commands.add("-y");

        String result=FFmpegUtils.execFFmpegCommand(commands);
        System.out.println(result);

    }

    /**
     * 合并多个音频
     */
    public String mergeMulAudios(String audiopath) throws Exception {
        List<File> totalFiles = FileUtil.loopFiles(audiopath, file -> file.isFile() && (file.getName().endsWith(".wav") || file.getName().endsWith(".mp3")));
        List<File> audioFiles = new ArrayList<>();
        for (File file : totalFiles) {
            //转换格式为wav
            if (file.getName().endsWith(".mp3")) {
                String newpath = new HandleAudioService().converAudio(file.getAbsolutePath());
                audioFiles.add(new File(newpath));
            }
            if (file.getName().endsWith(".wav")) {
                audioFiles.add(file);
            }
        }
        audioFiles.sort(new Comparator<File>() {
            @Override
            public int compare(File o1, File o2) {
                return o1.getName().compareTo(o2.getName());
            }
        });
        File outputFile = new File(audiopath + File.separator + "final.wav");
        List<AudioInputStream> audioInputStreams = new ArrayList<>();
        AudioInputStream mergedAudioStream = null;
        AudioInputStream audioInputStream = null;
        try {
            //系统支持的格式
            AudioFileFormat.Type[] types = AudioSystem.getAudioFileTypes();
            for (AudioFileFormat.Type type : types) {
                System.out.println(type.getExtension());
            }
            long totalLength = 0;
            AudioFormat audioFormat = null;
            // 读取每个音频文件，获取其音频格式和音频流
            for (File audioFile : audioFiles) {
                audioInputStream = AudioSystem.getAudioInputStream(audioFile);
                totalLength += audioInputStream.getFrameLength();
                audioFormat = audioInputStream.getFormat();
                audioInputStreams.add(audioInputStream);
            }
            // 创建新的音频格式和流
            boolean isSigned = audioFormat.getEncoding() == AudioFormat.Encoding.PCM_SIGNED;
            AudioFormat newAudioFormat = new AudioFormat(audioFormat.getSampleRate(),
                    audioFormat.getSampleSizeInBits(),
                    audioFormat.getChannels(),
                    isSigned,
                    audioFormat.isBigEndian());
            mergedAudioStream = new AudioInputStream(
                    new SequenceInputStream(Collections.enumeration(audioInputStreams)),
                    newAudioFormat,
                    totalLength
            );
            // 写入合并后的音频流到输出文件
            AudioSystem.write(mergedAudioStream, AudioFileFormat.Type.WAVE, outputFile);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            // 关闭所有音频流
            for (AudioInputStream ais : audioInputStreams) {
                ais.close();
            }
            mergedAudioStream.close();
            audioInputStream.close();
        }
        return outputFile.getAbsolutePath();
    }

    /**
     * 合并多个音频  ffmpeg -f concat -safe 0 -i filelist.txt -c copy output.mp3
     */
    public String mergeMulAudiosByFFmpeg(String audiopath) throws Exception {
        List<File> totalFiles = FileUtil.loopFiles(audiopath, file -> file.isFile() && (file.getName().endsWith(".wav") || file.getName().endsWith(".mp3")));
        List<File> audioFiles = new ArrayList<>();
        for (File file : totalFiles) {
            //转换格式为wav
            if (file.getName().endsWith(".mp3")) {
                String newpath = new HandleAudioService().converAudio(file.getAbsolutePath());
                audioFiles.add(new File(newpath));
            }
            if (file.getName().endsWith(".wav")) {
                audioFiles.add(file);
            }
        }
        audioFiles.sort(new Comparator<File>() {
            @Override
            public int compare(File o1, File o2) {
                return o1.getName().compareTo(o2.getName());
            }
        });
        StringBuffer buffer=new StringBuffer();
        for(File file:audioFiles){
            buffer.append("file");
            buffer.append(" ");
            buffer.append("'");
            buffer.append(file.getAbsolutePath());
            buffer.append("'");
            buffer.append("\n");
        }
        //保存txt
        String txtpath=audiopath+File.separator+"file.txt";
        FileWriter writer = null;
        try {
            writer = new FileWriter(txtpath, false);
            writer.write(buffer.toString());
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (writer != null) {
                writer.flush();
                writer.close();
            }
        }
        String finalPath=audiopath + File.separator + "final.wav";
        List<String> commands = new ArrayList<>();
        commands.add("ffmpeg");
        commands.add("-f");
        commands.add("concat");
        commands.add("-safe");
        commands.add("0");
        commands.add("-i");
        commands.add(txtpath);
        commands.add("-c");
        commands.add("copy");
        commands.add(finalPath);

        String result=FFmpegUtils.execFFmpegCommand(commands);
        System.out.println(result);

        return finalPath;
    }

    /**
     * 给音频添加空白前摇
     */
    public String mergePrefix2Audio(String audiopath) throws Exception {
        List<File> totalFiles = FileUtil.loopFiles(audiopath, file -> file.isFile() && (file.getName().endsWith(".wav") || file.getName().endsWith(".mp3")));
        List<File> audioFiles = new ArrayList<>();
        File audioFile = new File(audiopath);
        //转换格式为wav
        if (audioFile.getName().endsWith(".mp3")) {
            audiopath = new HandleAudioService().converAudio(audioFile.getAbsolutePath());
        }
        File outputFile = new File(audiopath.replace(".wav", "_final.wav"));
        List<AudioInputStream> audioInputStreams = new ArrayList<>();
        AudioInputStream mergedAudioStream = null;
        InputStream inputstream = null;
        try {
            inputstream = this.getClass().getClassLoader().getResourceAsStream("prefix.wav");
            //系统支持的格式
            AudioFileFormat.Type[] types = AudioSystem.getAudioFileTypes();
            for (AudioFileFormat.Type type : types) {
                System.out.println(type.getExtension());
            }
            long totalLength = 0;
            AudioFormat audioFormat = null;
            AudioInputStream audioInputStream = null;
            // 读取每个音频文件，获取其音频格式和音频流
            for (int i = 0; i < 2; i++) {
                if (i == 0) {
                    audioInputStream = AudioSystem.getAudioInputStream(inputstream);
                    totalLength += audioInputStream.getFrameLength();
                    audioFormat = audioInputStream.getFormat();
                    audioInputStreams.add(audioInputStream);

                } else {
                    audioInputStream = AudioSystem.getAudioInputStream(audioFile);
                    totalLength += audioInputStream.getFrameLength();
                    audioFormat = audioInputStream.getFormat();
                    audioInputStreams.add(audioInputStream);
                }
            }
            // 创建新的音频格式和流
            boolean isSigned = audioFormat.getEncoding() == AudioFormat.Encoding.PCM_SIGNED;
            AudioFormat newAudioFormat = new AudioFormat(audioFormat.getSampleRate(),
                    audioFormat.getSampleSizeInBits(),
                    audioFormat.getChannels(),
                    isSigned,
                    audioFormat.isBigEndian());
            mergedAudioStream = new AudioInputStream(
                    new SequenceInputStream(Collections.enumeration(audioInputStreams)),
                    newAudioFormat,
                    totalLength
            );
            // 写入合并后的音频流到输出文件
            AudioSystem.write(mergedAudioStream, AudioFileFormat.Type.WAVE, outputFile);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            // 关闭所有音频流
            for (AudioInputStream ais : audioInputStreams) {
                ais.close();
            }
            mergedAudioStream.close();
            inputstream.close();

        }
        return outputFile.getAbsolutePath();
    }

    /**
     * 合成多个视频
     *
     * @return
     * @throws Exception
     */
    public String batchMergeVedios(String vediopath) throws Exception {
        //筛选
        List<String> filePaths = new ArrayList<>();
        List<File> fileList = FileUtil.loopFiles(vediopath, file -> file.isFile() && file.getName().endsWith(".mp4"));
        for (File file : fileList) {
            filePaths.add(file.getAbsolutePath());
        }
        String outFilepath = recursionVideos(filePaths);
        return outFilepath;
    }

    /**
     * 通过ffmpeg合成多个视频
     * ffmpeg -i video1.mp4 -i video2.mp4 -filter_complex "[0:v][1:v]concat=n=2:v=1:a=0" -c:v libx264 -c:a copy final_video.mp4
     *
     * @return
     * @throws Exception
     */
    public String mergeMulVideosByFFmpeg(String vediopath) throws Exception {
        //筛选
        List<String> filePaths = new ArrayList<>();
        List<File> fileList = FileUtil.loopFiles(vediopath, file -> file.isFile() && file.getName().endsWith(".mp4"));
        for (File file : fileList) {
            filePaths.add(file.getAbsolutePath());
        }
        String outFilepath = recursionVideos(filePaths);
        return outFilepath;
    }

    /**
     * 递归操作
     *
     * @param fileList
     * @return
     */
    public String recursionVideos(List<String> fileList) {
        String resVideoPath = "";
        if (fileList.size() > 15) {
            //分割集合,每15个一组进行合并
            List<String> videoPaths = new ArrayList<>();
            List<List<String>> resList = splitList(fileList, 15);
            for (List<String> pageList : resList) {
                String newVideoPath = exexFfmpegByVideo(pageList);
                videoPaths.add(newVideoPath);
            }
            recursionVideos(videoPaths);
        } else {
            resVideoPath = exexFfmpegByVideo(fileList);
        }
        return resVideoPath;
    }

    /**
     * 执行视频合并命令
     */
    private String exexFfmpegByVideo(List<String> fileList) {
        String outFilepath = fileList.get(0).replace(".mp4", System.currentTimeMillis() + "_merge.mp4");
        File outFile = new File(outFilepath);
        if (outFile.exists()) {
            outFile.delete();
        }
        List<String> commands = new ArrayList<>();
        commands.add("ffmpeg");
        try {
            StringBuffer buffer = new StringBuffer();
            for (int i = 0; i < fileList.size(); i++) {
                commands.add("-i");
                commands.add(fileList.get(i));
                buffer.append("[");
                buffer.append(i);
                buffer.append(":");
                buffer.append("v");
                buffer.append("]");
            }
            commands.add("-filter_complex");
            commands.add("\"" + buffer.toString() + "concat=n=" + fileList.size() + ":v=1:a=0\"");
            commands.add("-c:v");
            commands.add("libx264");
            commands.add("-c:a");
            commands.add("copy");
            commands.add(outFilepath);

            String result=FFmpegUtils.execFFmpegCommand(commands);
            System.out.println(result);
        } catch (Exception e) {
            throw new RuntimeException("ffmpeg执行异常" + e.getMessage());
        }
        return outFilepath;
    }


    /**
     * 集合裁剪
     *
     * @param list
     * @param pageSize
     * @param <T>
     * @return
     */
    private <T> List<List<T>> splitList(List<T> list, int pageSize) {
        List<List<T>> pages = new ArrayList<>();
        int size = list.size();
        int pageCount = (size + pageSize - 1) / pageSize;
        for (int i = 0; i < pageCount; i++) {
            int fromIndex = i * pageSize;
            int toIndex = Math.min((i + 1) * pageSize, size);
            List<T> page = list.subList(fromIndex, toIndex);
            pages.add(page);
        }
        return pages;
    }


    /**
     * 合成两个视频
     *
     * @return
     * @throws Exception
     */
    public String mergeDoubleVedios(String firstVideo, String secondVideo) throws Exception {
        boolean isCreated = true;
        FrameRecorder recorder = null;
        File firstVideoFile = new File(firstVideo);
        String outFilepath = firstVideoFile.getParent() + File.separator + "merge.mp4";
        FrameGrabber firstGrabber = null;
        FrameGrabber secondGrabber = null;
        try {
            //抓取视频帧
            firstGrabber = new FFmpegFrameGrabber(firstVideo);
            secondGrabber = new FFmpegFrameGrabber(secondVideo);
            firstGrabber.start();
            secondGrabber.start();

            if (recorder == null) {
                //创建录制
                recorder = new FFmpegFrameRecorder(outFilepath,
                        firstGrabber.getImageWidth(), firstGrabber.getImageHeight());
                recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
                recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);
                recorder.setFormat("mp4");
                recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
                recorder.setAudioChannels(1);
                recorder.setFrameRate(30);
                // 10kb/s 这个说明视频每秒大小，值越大图片转过来的压缩率就越小质量就会越高
                recorder.setVideoBitrate(3000000);
                recorder.start();
            }
            Frame frame;
            //分别录入两个视频
            while ((frame = firstGrabber.grabFrame()) != null) {
                recorder.record(frame);
            }
            while ((frame = secondGrabber.grabFrame()) != null) {
                recorder.record(frame);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (firstGrabber != null) {
                    firstGrabber.release();
                    firstGrabber.stop();
                }
                if (secondGrabber != null) {
                    secondGrabber.release();
                    secondGrabber.stop();
                }
                recorder.stop();
                if (recorder != null) {
                    recorder.release();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return outFilepath;
    }

    /**
     * 批量合成视频和音频
     *
     * @return
     * @throws Exception
     */
    public boolean batchMergeVediosAndAudio(String vedioFolderpath) throws Exception {
        boolean isCreated = true;
        //过滤视频
        List<File> videoList = FileUtil.loopFiles(vedioFolderpath, file -> file.isFile() && file.getName().endsWith(".mp4"));
        if (videoList == null || videoList.size() <= 0) {
            throw new RuntimeException("合并操作:无可操作的视频文件");
        }
        //过滤音频
        List<File> audiolist = FileUtil.loopFiles(vedioFolderpath, file -> file.isFile() && (file.getName().endsWith(".wav")||file.getName().endsWith(".mp3")));
        if (audiolist == null || audiolist.size() <= 0) {
            throw new RuntimeException("合并操作:无可操作的音频文件");
        }
        //生成需要合并的视频和音频
        List<Map<String, String>> mergeMapList = new ArrayList<>();
        for (File videoFile : videoList) {
            String videofilename = videoFile.getName().substring(0, videoFile.getName().indexOf("."));
            for (File audioFile : audiolist) {
                String audiofilename = audioFile.getName().substring(0, audioFile.getName().indexOf("."));
                if (videofilename.equals(audiofilename)) {
                    Map<String, String> resMap = new HashMap<>();
                    resMap.put("audio", audioFile.getAbsolutePath());
                    resMap.put("video", videoFile.getAbsolutePath());
                    mergeMapList.add(resMap);
                    break;
                }
            }
        }
        //判断是否有数据
        if (mergeMapList.size() <= 0) {
            throw new RuntimeException("合并操作:无可操作的数据");
        }
        List<String> tips = new ArrayList<>();
        for (Map<String, String> paramMap : mergeMapList) {
            String videoFilepath = "";
            try {
                videoFilepath = paramMap.get("video");
                //音频
                String audioPath = paramMap.get("audio");
                new HandleVideoService().mergeVediosAndAudio(videoFilepath, audioPath);
            } catch (Exception e) {
                tips.add("文件[" + videoFilepath + "]合并异常:" + e.toString());
            }
        }
        if (tips.size() > 0) {
            throw new RuntimeException(tips.toString());
        }
        return isCreated;
    }

    /**
     * 筛选帧率是30的视频
     */
    private List<String> filterVideos(String vediopath) throws Exception {
        List<File> fileList = FileUtil.loopFiles(vediopath, file -> file.isFile() && file.getName().endsWith(".mp4"));
        List<String> Mp4List = new ArrayList<>();
        for (File file : fileList) {
            FrameGrabber grabber = null;
            try {
                grabber = new FFmpegFrameGrabber(file.getAbsolutePath());
                grabber.start();
                double framrate = grabber.getFrameRate();
                if (framrate == 30) {
                    Mp4List.add("file \'" + file.getAbsolutePath() + "\'");
                }
            } catch (FrameGrabber.Exception e) {
                throw new RuntimeException(e);
            } finally {
                if (grabber != null) {
                    grabber.close();
                }
            }
        }
        return Mp4List;
    }

    /**
     * 分离出视频
     *
     * @param videoFolderpath
     * @throws Exception
     */
    public String splitSingleVideo(String videoFolderpath) throws Exception {
        String outfilepath = videoFolderpath.replace(".mp4", "_fenli.mp4");

        List<String> commands = new ArrayList<>();
        commands.add("ffmpeg");
        commands.add("-i");
        commands.add(videoFolderpath);
        commands.add("-vcodec");
        commands.add("copy");
        commands.add("-an");
        commands.add(outfilepath);

        String result=FFmpegUtils.execFFmpegCommand(commands);
        System.out.println(result);

        return outfilepath;

        // 音频、视频都保留原格式。 这种方式转换最快。
        // ffmpeg -i test.mp4 -acodec copy -vcodec copy -an video.mp4
//这里也可以加上 -ss 或者 -t 参数只保留视频的一部分。 视频裁剪用的就是这两个参数
// 只保留音频。 转换后只有音频没有视频
        //   ffmpeg -i test.mp4 -acodec copy -vn audio.mp4
// 只保留视频。 转换后只有视频没有音频
        //    ffmpeg -i test.mp4 -vcodec copy -an video.mp4


// 保留编码格式
        // ffmpeg -i test.mp4 -vcodec copy -an test_copy.h264


// 强制格式
        //  ffmpeg -i test.mp4 -vcodec libx264 -an test.h264
        //  ffmpeg -i test.mp4 -vcodec flv -an test.flv


//保留编码格式
        //    ffmpeg -i test.mp4 -acodec copy -vn test.aac

//强制格式
        //   ffmpeg -i test.mp4 -acodec libmp3lame -vn test.mp3
        //   ffmpeg -i test.mp4 -acodec pcm_s16le -vn test.wav


    }

    /**
     * 从多个视频分离音频
     *
     * @param vedioFolderpath
     * @param type
     * @throws Exception
     */
    public void splitBatchAudios(String vedioFolderpath, String type) throws Exception {
        List<File> fileList = FileUtil.loopFiles(vedioFolderpath, file -> file.isFile() && file.getName().endsWith(".mp4"));
        for (File file : fileList) {
            splitSingleAudio(file.getAbsolutePath(), type);
        }
    }

    /**
     * 分离单个视频为音频
     *
     * @param videoFolderpath
     * @throws Exception
     */
    public void splitSingleAudio(String videoFolderpath, String type) throws Exception {
        List<String> commands = new ArrayList<>();
        if (type.equals("mp3")) {
            String outfilepath = videoFolderpath.replace(".mp4", ".mp3");
            commands.add("ffmpeg");
            commands.add("-i");
            commands.add(videoFolderpath);
            commands.add("-acodec");
            commands.add("libmp3lame");
            commands.add("-vn");
            commands.add(outfilepath);
        }
        if (type.equals("wav")) {
            String outfilepath = videoFolderpath.replace(".mp4", ".wav");

            commands.add("ffmpeg");
            commands.add("-i");
            commands.add(videoFolderpath);
            commands.add("-acodec");
            commands.add("pcm_s16le");
            commands.add("-vn");
            commands.add(outfilepath);

        }

        String result=FFmpegUtils.execFFmpegCommand(commands);
        System.out.println(result);
        // 音频、视频都保留原格式。 这种方式转换最快。
        // ffmpeg -i test.mp4 -acodec copy -vcodec copy -an video.mp4
//这里也可以加上 -ss 或者 -t 参数只保留视频的一部分。 视频裁剪用的就是这两个参数
// 只保留音频。 转换后只有音频没有视频
        //   ffmpeg -i test.mp4 -acodec copy -vn audio.mp4
// 只保留视频。 转换后只有视频没有音频
        //    ffmpeg -i test.mp4 -vcodec copy -an video.mp4


// 保留编码格式
        // ffmpeg -i test.mp4 -vcodec copy -an test_copy.h264


// 强制格式
        //  ffmpeg -i test.mp4 -vcodec libx264 -an test.h264
        //  ffmpeg -i test.mp4 -vcodec flv -an test.flv


//保留编码格式
        //    ffmpeg -i test.mp4 -acodec copy -vn test.aac

//强制格式
        //   ffmpeg -i test.mp4 -acodec libmp3lame -vn test.mp3
        //   ffmpeg -i test.mp4 -acodec pcm_s16le -vn test.wav


    }


    /**
     * 合成音频和视频
     *
     * @param videoPath
     * @param audioPath
     * @return
     * @throws Exception
     */
    public boolean mergeAudioAndVideo(String videoPath, String audioPath) throws Exception {
        String output = videoPath.replace(".mp4", "_final.mp4");
        File outputfile = new File(output);
        if (outputfile.exists()) {
            outputfile.delete();
        }
        boolean isCreated = true;
        File file = new File(videoPath);
        if (!file.exists()) {
            return false;
        }
        FFmpegFrameGrabber grabberVideo = null;
        FFmpegFrameGrabber grabberAudio = null;
        try {
            //抓取视频帧
            grabberVideo = new FFmpegFrameGrabber(videoPath);
            //抓取音频帧
            grabberAudio = new FFmpegFrameGrabber(audioPath);
            grabberVideo.start();
            grabberAudio.start();
            //获取时长,以短的文件为主进行截取
            long durationVideo = grabberVideo.getFormatContext().duration() / 1000000;
            long durationAudio = grabberAudio.getFormatContext().duration() / 1000000;
            if(durationVideo!=durationAudio){
                if (durationVideo > durationAudio) {//音频短则以音频长度为主
                    //截取视频
                    videoPath = new VedioUtils().cutVideoByDurationAndStartZ(videoPath, durationAudio);
                } else {
                    //截取音频
                    audioPath = new HandleAudioService().cutAudioByStart(audioPath, durationVideo, "wav");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (grabberVideo != null) {
                grabberVideo.stop();
                grabberVideo.release();
            }
            if (grabberAudio != null) {
                grabberAudio.stop();
                grabberAudio.release();
            }
        }
        FrameRecorder recorder = null;
        FFmpegFrameGrabber grabber1 = null;
        FFmpegFrameGrabber grabber2 = null;
        try {
            //抓取视频帧
            grabber1 = new FFmpegFrameGrabber(videoPath);
            //抓取音频帧
            grabber2 = new FFmpegFrameGrabber(audioPath);
            grabber1.start();
            grabber2.start();
            //创建录制
            recorder = new FFmpegFrameRecorder(output,
                    grabber1.getImageWidth(), grabber1.getImageHeight(),
                    grabber2.getAudioChannels());
            recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
            recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);
            recorder.setFormat("mp4");
            recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
            recorder.setFrameRate(30);
            // 10kb/s 这个说明视频每秒大小，值越大图片转过来的压缩率就越小质量就会越高
            recorder.setVideoBitrate(3000000);
            recorder.setAudioChannels(2);
            recorder.setAudioQuality(0);
            recorder.setSampleRate(grabber2.getSampleRate());
            recorder.start();

            Frame frame1;
            Frame frame2;
            //先录入视频
            while ((frame1 = grabber1.grabFrame()) != null) {
                recorder.record(frame1);
            }
            //然后录入音频
            while ((frame2 = grabber2.grabFrame()) != null) {
                recorder.record(frame2);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (recorder != null) {
                    recorder.stop();
                    recorder.release();
                }
                if (grabber1 != null) {
                    grabber1.stop();
                    grabber1.release();
                }
                if (grabber2 != null) {
                    grabber2.stop();
                    grabber2.release();
                }
            } catch (FrameRecorder.Exception e) {
                e.printStackTrace();
            }
        }
        return isCreated;
    }

    /**
     * 视频剪切仅支持无音频文件,有音频会截取失真
     *
     * @param videoFilepath
     * @param paramstartTimes
     * @param paramdurations
     */
    public String cutVideo(String videoFilepath, String paramstartTimes, String paramdurations) {
        String[] times = paramstartTimes.split(":");
        String[] durations = paramdurations.split(":");
        int startTime = Integer.valueOf(times[0]) * 3600 + Integer.valueOf(times[1]) * 60 + Integer.valueOf(times[2]);
        int duration = Integer.valueOf(durations[0]) * 3600 + Integer.valueOf(durations[1]) * 60 + Integer.valueOf(durations[2]);

        String outputVideo = videoFilepath.replace(".mp4", "_cutvodeo.mp4");
        File file = new File(outputVideo);
        if (file.exists()) {
            file.delete();
        }
        // startTime开始时间（以秒为单位）
        //duration 截取视频的时长（以秒为单位）
        FFmpegFrameGrabber grabber = null;
        FFmpegFrameRecorder recorder = null;
        try {
            grabber = new FFmpegFrameGrabber(videoFilepath);
            grabber.start();
            int totalduration = (int) grabber.getLengthInTime() / 1000000;
            recorder = new FFmpegFrameRecorder(outputVideo, grabber.getImageWidth(), grabber.getImageHeight());
            recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);//avcodec.AV_CODEC_ID_H264
            recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);//avutil.AV_PIX_FMT_YUV420P
            recorder.setFormat("mp4");//"mp4"
            recorder.setAudioChannels(grabber.getAudioChannels());
            recorder.setFrameRate(grabber.getFrameRate());
            // 10kb/s 这个说明视频每秒大小，值越大图片转过来的压缩率就越小质量就会越高
            recorder.setVideoBitrate(3000000);
            recorder.start();

            int framerate = (int) grabber.getFrameRate();
            int frameCount = duration * framerate;
            int totalframeCount = totalduration * framerate;
            Frame frame;
            for (int i = 0; i < totalframeCount; i++) {
                frame = grabber.grab();
                if (frame == null) {
                    break;
                }
                if (i >= startTime * framerate && i <= frameCount) {
                    recorder.record(frame);
                }
            }
            System.out.println("视频截取成功！");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (recorder != null) {
                    recorder.stop();
                    recorder.release();
                }
                if (grabber != null) {
                    grabber.stop();
                    grabber.release();
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return outputVideo;
    }

    /**
     * 截取有音频视频
     *
     * @param videoFilepath
     * @param paramstartTimes
     * @param paramdurations
     */
    public String cutVideoByFFmpeg(String videoFilepath, String paramstartTimes, String paramdurations) throws Exception {
        String outputVideo ="";
        if(videoFilepath.endsWith(".mp4")){
            outputVideo = videoFilepath.replace(".mp4", "_cutvodeo.mp4");
        }
        if(videoFilepath.endsWith(".mkv")){
            outputVideo = videoFilepath.replace(".mkv", "_cutvodeo.mkv");
        }
        File file = new File(outputVideo);
        if (file.exists()) {
            file.delete();
        }

        List<String> commands = new ArrayList<>();
        commands.add("ffmpeg");
        commands.add("-i");
        commands.add(videoFilepath);
        commands.add("-c:v");
        commands.add("libx264");
        commands.add("-crf");
        commands.add("18");
        commands.add("-ss");
        commands.add(paramstartTimes);
        commands.add("-to");
        commands.add(paramdurations);
        commands.add(outputVideo);

        String res = FFmpegUtils.execFFmpegCommand(commands);
        System.out.println(res);

        return outputVideo;
    }

    /**
     * 截取有音频视频并指定路径
     *
     * @param videoFilepath
     * @param paramstartTimes
     * @param paramdurations
     */
    public String cutVideoByFFmpegByOutpath(String videoFilepath, String paramstartTimes, String paramdurations,String outPath) throws Exception {
        File file = new File(outPath);
        if (file.exists()) {
            file.delete();
        }

        List<String> commands = new ArrayList<>();
        commands.add("ffmpeg");
        commands.add("-i");
        commands.add(videoFilepath);
        commands.add("-c:v");
        commands.add("libx264");
        commands.add("-crf");
        commands.add("18");
        commands.add("-ss");
        commands.add(paramstartTimes);
        commands.add("-to");
        commands.add(paramdurations);
        commands.add(outPath);

        String res = FFmpegUtils.execFFmpegCommand(commands);
        System.out.println(res);

        return outPath;
    }

    /**
     * 从0位置截取指定长度的视频
     *
     * @param videoFilepath
     */
    public String cutVideoByDurationAndStartZ(String videoFilepath, long duration) {
        String outputVideo = videoFilepath.replace(".mp4", "_cutvodeo.mp4");
        File file = new File(outputVideo);
        if (file.exists()) {
            file.delete();
        }
        // startTime开始时间（以秒为单位）
        //duration 截取视频的时长（以秒为单位）
        FFmpegFrameGrabber grabber = null;
        FFmpegFrameRecorder recorder = null;
        try {
            grabber = new FFmpegFrameGrabber(videoFilepath);
            grabber.start();
            int totalduration = (int) grabber.getLengthInTime() / 1000000;
            recorder = new FFmpegFrameRecorder(outputVideo, grabber.getImageWidth(), grabber.getImageHeight());
            recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);//avcodec.AV_CODEC_ID_H264
            recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);//avutil.AV_PIX_FMT_YUV420P
            recorder.setFormat("mp4");//"mp4"
            recorder.setAudioChannels(grabber.getAudioChannels());
            recorder.setFrameRate(grabber.getFrameRate());
            // 10kb/s 这个说明视频每秒大小，值越大图片转过来的压缩率就越小质量就会越高
            recorder.setVideoBitrate(3000000);
            recorder.start();

            int framerate = (int) grabber.getFrameRate();
            int frameCount = (int) duration * framerate;
            int totalframeCount = totalduration * framerate;
            Frame frame;
            for (int i = 0; i < totalframeCount; i++) {
                frame = grabber.grab();
                if (frame == null) {
                    break;
                }
                if (i >= 0 && i <= frameCount) {
                    recorder.record(frame);
                }
            }
            System.out.println("视频截取成功！");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (recorder != null) {
                    recorder.stop();
                    recorder.release();
                }
                if (grabber != null) {
                    grabber.stop();
                    grabber.release();
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return outputVideo;
    }


}
